package net.pimpas.validation.serviceprovider.impl;

import net.pimpas.core.configuration.exception.ConfigurationException;
import net.pimpas.core.serviceprovider.ServiceProviderAnnotation;
import net.pimpas.core.serviceprovider.instancetype.ServiceProviderInstanceType;
import net.pimpas.logging.serviceprovider.LoggingServiceProvider;
import net.pimpas.logging.serviceprovider.LoggingServiceProviderFactoryImpl;
import net.pimpas.util.reflection.ReflectionUtil;
import net.pimpas.validation.Validation;
import net.pimpas.validation.exception.ValidationException;
import net.pimpas.validation.result.ValidationResult;
import net.pimpas.validation.result.impl.DefaultValidationResult;
import net.pimpas.validation.serviceprovider.ValidationServiceProvider;

@ServiceProviderAnnotation(
		instanceType=ServiceProviderInstanceType.SINGLETON,
		serviceProviderType=ValidationServiceProvider.class
)
public class ValidationServiceProviderImpl implements ValidationServiceProvider {
	
	private static final LoggingServiceProvider logger = 
		LoggingServiceProviderFactoryImpl.getLoggingServiceProvider(ValidationServiceProviderImpl.class);

	public void config() throws ConfigurationException {
	}

	public boolean isTerminated() {
		return false;
	}
	
	public ValidationResult validate(ValidationResult result, Validation validation, Object... parameters) throws ValidationException {
		assert(validation!=null);
		
		logger.debug("[Invoking validate for {"+validation+"}]");
		try {
			validation.validate(result);
		} catch(Exception ex) {
			if(ReflectionUtil.isSubclass(ex.getClass(), ValidationException.class))
				throw (ValidationException) ex;
			
			throw new ValidationException(ex);
		}
		if(result.hasErrors()) {
			logger.debug("[Errors found in {"+validation+"} skipping childrens!]");
			return result;
		}
		
		for(Validation v: validation.getChildrens()) {
			logger.debug("[Invoking validate for child {"+v+"}]");
			try {
				v.validate(result, parameters);
			} catch(Exception ex) {
				if(ReflectionUtil.isSubclass(ex.getClass(), ValidationException.class))
					throw (ValidationException) ex;
				
				throw new ValidationException(ex);
			}
		}
		
		return result;
	}

	public ValidationResult validate(Validation validation, Object... parameters) throws ValidationException {
		return this.validate(new DefaultValidationResult(), validation, parameters);
	}
}